﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using TeacherLeftHand.DataAccess;
using TeacherLeftHand.Messages;
using TeacherLeftHand.Model;
using TeacherLeftHand.Util;

namespace TeacherLeftHand.ViewModel
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>

    /// </para>
    /// </summary>
    public class KnowledgeItemManageViewModel : ViewModelBase
    {
        #region constructor
        public KnowledgeItemManageViewModel()
        {
            // initialize properties and private fields
            _maxTopicNo = _kiAccessor.GetMaxTopicNo();
            _subjectList = _kiAccessor.GetSubjectList();
            _subjectList.Insert(0, "");
            SearchCondition = new KISearchCondition();
            LoadAll();
            if (KIList.Count > 0)
            {
                SelectedKnowledgeItem = new KnowledgeItem(KIList[0]);
            }

            #region paging
            FirstPageCommand = new RelayCommand(() => CustomPaging((int)PagingMode.First));

            PrevPageCommand = new RelayCommand(() => CustomPaging((int)PagingMode.Previous));

            NextPageCommand = new RelayCommand(() => CustomPaging((int)PagingMode.Next));

            LastPageCommand = new RelayCommand(() => CustomPaging((int)PagingMode.Last));

            PageChanged = new RelayCommand<string>(text =>
            {
                try
                {
                    var temp = int.Parse(text);
                    if (temp > 0 && temp <= TotalPages)
                    {
                        CurrentPage = temp;
                        RefreshPaging();
                    }
                    else
                    {
                        CurrentPage = _currentPage;
                    }
                }
                catch (FormatException e)
                {
                    CurrentPage = _currentPage;
                }
            });
            #endregion


            // Commands
            CreateCommand = new RelayCommand(Create);

            Messenger.Default.Register<UpdateKIMessage>(this, UpdateKIList);
        }

        #endregion

        #region Properties

        private KnowledgeItem _selectedKnowledgeItem = new KnowledgeItem();
        private ObservableCollection<KnowledgeItem> _kiList = new ObservableCollection<KnowledgeItem>();
        private KISearchCondition _searchCondition = new KISearchCondition();


        /// <summary>
        /// The <see cref="IsEditButtonEnabled" /> property's name.
        /// </summary>
        public const string IsEditButtonEnabledPropertyName = "IsEditButtonEnabled";

        private bool _isEditButtonEnabled = true;

        /// <summary>
        /// Gets the IsEditButtonEnabled property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public bool IsEditButtonEnabled
        {
            get
            {
                return _isEditButtonEnabled;
            }

            set
            {
                if (_isEditButtonEnabled == value)
                {
                    return;
                }

                _isEditButtonEnabled = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(IsEditButtonEnabledPropertyName);
            }
        }

        public ICommand EditCommand
        {
            get;
            private set;
        }

        public const string SelectedKnowledgeItemPropertyName = "SelectedKnowledgeItem";
        public KnowledgeItem SelectedKnowledgeItem
        {
            get
            {
                return _selectedKnowledgeItem;
            }
            set
            {
                if (_selectedKnowledgeItem != value)
                {
                    _selectedKnowledgeItem = value;
                    RaisePropertyChanged(SelectedKnowledgeItemPropertyName);
                    RaisePropertyChanged(HasKIsPropertyName);
                    Messenger.Default.Send(value, SelectedKnowledgeItemPropertyName);
                }
            }
        }

        private ICommand _deleteCommand;
        public ICommand DeleteCommand
        {
            get
            {
                if (_deleteCommand == null)
                {
                    _deleteCommand = new RelayCommand(() =>
                    {
                        var result = MessageBox.Show(DataHelper.DeleteConfirmationMessage,
                                        DataHelper.DeleteConfirmationCaption,
                                        MessageBoxButton.OKCancel,
                                        MessageBoxImage.Warning);
                        if (result == MessageBoxResult.Cancel) return;

                        var msg = new UpdateKIMessage
                        {
                            Action = UpdateAction.Delete,
                            KnowledgeItem = SelectedKnowledgeItem
                        };
                        Messenger.Default.Send(msg);
                    });
                }
                return _deleteCommand;
            }
        }

        public const string KIListPropertyName = "KIList";
        public ObservableCollection<KnowledgeItem> KIList
        {
            get
            {
                return _kiList;
            }
            set
            {
                _kiList = value;
                RaisePropertyChanged(KIListPropertyName);
                RefreshPaging();
            }
        }

        public ICommand CreateCommand
        {
            get;
            private set;
        }

        private ICommand _searchCommand;
        public ICommand SearchCommand
        {
            get
            {
                if (_searchCommand == null)
                {
                    _searchCommand = new RelayCommand(() =>
                    {
                        //if (!SearchCondition.AdvancedSearchMode)
                        //{
                        //    var keyword = SearchCondition.Keyword;
                        //    SearchCondition = new KISearchCondition { Keyword = keyword };
                        //}
                        var result = new ObservableCollection<KnowledgeItem>();
                        var worker = new BackgroundWorker();
                        worker.DoWork += (s, oe) =>
                                             {
                                                 if (SearchCondition.AdvancedSearchMode)
                                                 {
                                                     result = AdvanceSearch(SearchCondition);
                                                 }
                                                 else
                                                 {
                                                     result = Search(SearchCondition);
                                                 }
                                             };
                        worker.RunWorkerCompleted += (s, oe) =>
                                                         {
                                                             if (result.Count == 0)
                                                                 LoadAll();
                                                             else
                                                             {
                                                                 _kiList = result;
                                                                 SelectedKnowledgeItem = _kiList.Count > 0
                                                                                             ? new KnowledgeItem(_kiList[0])
                                                                                             : new KnowledgeItem();

                                                                 RaisePropertyChanged(KIListPropertyName);
                                                             }
                                                         };
                        worker.RunWorkerAsync();
                    });

                }
                return _searchCommand;
            }

        }

        public const string SearchConditionPropertyName = "SearchCondition";
        public KISearchCondition SearchCondition
        {
            get { return _searchCondition; }
            set
            {
                if (_searchCondition != value)
                {
                    _searchCondition = value;
                    RaisePropertyChanged(SearchConditionPropertyName);
                }
            }
        }

        private ObservableCollection<int> _classLevelList = DataHelper.ClassLevelList;

        /// <summary>
        /// Gets the ClassLevelList property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public int MaxClassLevel
        {
            get
            {
                return _classLevelList.Last();
            }
        }

        /// <summary>
        /// The <see cref="SubjectList" /> property's name.
        /// </summary>
        public const string SubjectListPropertyName = "SubjectList";

        private ObservableCollection<string> _subjectList = new ObservableCollection<string>();

        /// <summary>
        /// Gets the SubjectList property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public ObservableCollection<string> SubjectList
        {
            get
            {
                return _subjectList;
            }

            set
            {
                if (_subjectList == value)
                {
                    return;
                }

                _subjectList = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(SubjectListPropertyName);
            }
        }

        private int _maxTopicNo = 1;

        /// <summary>
        /// Gets the TopicList property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public int MaxTopic
        {
            get { return _maxTopicNo; }
        }

        /// <summary>
        /// The <see cref="IsLoading" /> property's name.
        /// </summary>
        public const string IsLoadingPropertyName = "IsLoading";

        private bool _isLoading;

        /// <summary>
        /// Gets the IsLoading property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public bool IsLoading
        {
            get
            {
                return _isLoading;
            }

            set
            {
                if (_isLoading == value)
                {
                    return;
                }

                _isLoading = value;
                // Update bindings, no broadcast
                RaisePropertyChanged(IsLoadingPropertyName);
            }
        }
        #endregion

        #region Members

        private readonly KnowledgeItemAccessor _kiAccessor = new KnowledgeItemAccessor();
        public const string HasKIsPropertyName = "HasKIs";
        /// <summary>
        /// Gets the HasKIs property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public bool HasKIs
        {
            get
            {
                if (SelectedKnowledgeItem == null) return false;
                if (SelectedKnowledgeItem.ID == -1) return false;
                return KIList.Count > 0;
            }
        }
        #endregion

        #region Methods
        public ObservableCollection<KnowledgeItem> Search(KISearchCondition searchCondition)
        {
            return _kiAccessor.Search(searchCondition);
        }

        public ObservableCollection<KnowledgeItem> AdvanceSearch(KISearchCondition searchCondition)
        {
            return _kiAccessor.AdvanceSearch(searchCondition);
        }

        public bool Delete(KnowledgeItem item)
        {
            return _kiAccessor.Delete(item);
        }

        public void Create()
        {
            //Messenger.Default.Send(new CreateNewKIWindowMessage { Action = WindowAction.OpenCreate });
            // send CREATE message to knoweldge item view 
            SelectedKnowledgeItem = new KnowledgeItem();
            Messenger.Default.Send(new KnowledgeItemViewMessage());
        }

        private void LoadAll()
        {
            var worker = new BackgroundWorker();
            var result = new ObservableCollection<KnowledgeItem>();
            worker.DoWork += (s, oe) =>
                                 {
                                     result = _kiAccessor.GetAll();
                                 };
            worker.RunWorkerCompleted += (s, oe) =>
                                             {
                                                 KIList = result;
                                                 IsLoading = false;
                                                 try
                                                 {
                                                     SelectedKnowledgeItem = KIList[0];
                                                 } catch (ArgumentOutOfRangeException)
                                                 {
                                                     SelectedKnowledgeItem = null;
                                                 }
                                             };
            IsLoading = true;
            worker.RunWorkerAsync();
        }

        private void UpdateKIList(UpdateKIMessage msg)
        {
            switch (msg.Action)
            {
                case UpdateAction.Add:
                    if (KIList == null) break;
                    KIList.Add(msg.KnowledgeItem);
                    RefreshPaging();
                    RaisePropertyChanged("KIList");
                    RaisePropertyChanged(HasKIsPropertyName);
                    SelectedKnowledgeItem = new KnowledgeItem(KIList[0]);
                    break;

                case UpdateAction.Delete:
                    if (KIList.Count <= 0) break;
                    KIList.Remove(msg.KnowledgeItem);
                    Delete(msg.KnowledgeItem);
                    RefreshPaging();
                    RaisePropertyChanged("KIList");
                    RaisePropertyChanged(HasKIsPropertyName);
                    SelectedKnowledgeItem = KIList.Count > 0 ? new KnowledgeItem(KIList[0]) : new KnowledgeItem();
                    break;

                case UpdateAction.Update:
                    if (KIList == null) break;
                    if (KIList.Count <= 0) break;
                    var index = KIList.IndexOf(KIList.Where(x => x.ID == msg.KnowledgeItem.ID).Select(x => x).First());
                    KIList[index] = new KnowledgeItem(msg.KnowledgeItem);
                    //RaisePropertyChanged("KIList");
                    break;
                default:
                    throw new NotSupportedException("Unknown Update Action");
            }

        }
        #endregion

        #region PAGING ***********************************************************************************
        private int _currentPage = 1;
        private int _totalPages;
        const int RECORDS_PER_PAGE = 10;
        private enum PagingMode { Next = 2, Previous = 3, First = 1, Last = 4 };
        private ObservableCollection<KnowledgeItem> _pagedKIList = new ObservableCollection<KnowledgeItem>();
        public ObservableCollection<KnowledgeItem> PagedKIList
        {
            get
            {
                return _pagedKIList;
            }
            set
            {
                _pagedKIList = value;
                RaisePropertyChanged("PagedKIList");
            }
        }
        public ICommand FirstPageCommand
        {
            get;
            private set;
        }
        public ICommand PrevPageCommand
        {
            get;
            private set;
        }
        public ICommand NextPageCommand
        {
            get;
            private set;
        }
        public ICommand LastPageCommand
        {
            get;
            private set;
        }
        public ICommand PageChanged
        {
            get;
            private set;
        }
        private void CustomPaging(int mode)
        {

            switch (mode)
            {
                case (int)PagingMode.Next:
                    //if (_kiList.Count > (_currentPage * RECORDS_PER_PAGE))
                    //{
                    //    _pagedKIList.Clear();

                    //    if (_kiList.Count >= ((_currentPage * RECORDS_PER_PAGE) + RECORDS_PER_PAGE))
                    //    {
                    //        for (int i = _currentPage * RECORDS_PER_PAGE; i < ((_currentPage * RECORDS_PER_PAGE) + RECORDS_PER_PAGE); i++)
                    //        {
                    //            _pagedKIList.Add(KIList[i]);
                    //        }
                    //    }
                    //    else
                    //    {
                    //        for (int i = _currentPage * RECORDS_PER_PAGE; i < KIList.Count; i++)
                    //        {
                    //            _pagedKIList.Add(KIList[i]);
                    //        }
                    //    }

                    //    CurrentPage++;
                    //}
                    if (CurrentPage < TotalPages)
                    {
                        CurrentPage++;
                    }
                    break;
                case (int)PagingMode.Previous:
                    //if (_currentPage > 1)
                    //{
                    //    _pagedKIList.Clear();
                    //    CurrentPage--;
                    //    for (int i = ((_currentPage * RECORDS_PER_PAGE) - RECORDS_PER_PAGE); i < (_currentPage * RECORDS_PER_PAGE); i++)
                    //    {
                    //        _pagedKIList.Add(_kiList[i]);
                    //    }

                    //}
                    if (CurrentPage > 1)
                    {
                        CurrentPage--;
                    }
                    break;
                case (int)PagingMode.First:
                    //CurrentPage = 2;
                    //CustomPaging((int)PagingMode.Previous);
                    if (TotalPages > 0)
                    {
                        CurrentPage = 1;
                    }
                    break;
                case (int)PagingMode.Last:
                    //CurrentPage = _totalPages - 1;
                    //CustomPaging((int)PagingMode.Next);
                    if (TotalPages > 0)
                    {
                        CurrentPage = TotalPages;
                    }
                    break;
            }
            RefreshPaging();
        }

        private void RefreshPaging()
        {

            try
            {
                _pagedKIList.Clear();
                if (_kiList.Count > 0)
                {
                    TotalPages = (_kiList.Count % RECORDS_PER_PAGE == 0) ? _kiList.Count / RECORDS_PER_PAGE : _kiList.Count / RECORDS_PER_PAGE + 1;
                    CurrentPage = _currentPage < _totalPages ? _currentPage : _totalPages;
                    if (_currentPage == 0)
                    {
                        CurrentPage = 1;
                    }
                    if (_kiList.Count >= _currentPage * RECORDS_PER_PAGE)
                    {
                        for (int i = (_currentPage - 1) * RECORDS_PER_PAGE; i < _currentPage * RECORDS_PER_PAGE; i++)
                        {
                            _pagedKIList.Add(_kiList[i]);
                        }
                    }
                    else
                    {
                        for (int i = (_currentPage - 1) * RECORDS_PER_PAGE; i < _kiList.Count; i++)
                        {
                            _pagedKIList.Add(_kiList[i]);
                        }
                    }
                }
                else
                {
                    TotalPages = 0;
                    CurrentPage = 0;
                }
                //try
                //{
                //if (_kiList.Count > 0)
                //{
                //    if(_currentPage>0)
                //    {
                //        _currentPage--;
                //    }

                //    CustomPaging((int)PagingMode.Next);
                //}
                //else
                //{
                //    CurrentPage = 0;
                //}
                //else
                //{
                //    MessageBox.Show("No Records Exists for the selected category");
                //}
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public int CurrentPage
        {
            get
            {
                return _currentPage;
            }
            set
            {
                _currentPage = value;
                RaisePropertyChanged("CurrentPage");
            }
        }

        public int TotalPages
        {
            get
            {
                return _totalPages;
            }
            set
            {
                _totalPages = value;
                RaisePropertyChanged("TotalPages");
            }
        }
        #endregion paging
    }
}